package com.zhiyou100.test.test04.proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author yang
 * @className Demo03
 * @packageName com.zhiyou100.test.test04.proxy
 * @Description TODO cglib 代理 子类代理
 * @date 2020-08-11 14:20
 */
public class Demo03 {
    /**
     * cglib 代理 子类代理
     * 特点：创建目标类的子类，通过重写父类方法失信目标类功能的扩展
     */
    public static void main(String[] args) {
        // 6、测试

        // 定义目标类对象
        Teacher zhang = new Teacher(32, "张三");

        // 创建工厂类对象并关联目标类对象
        SonProxyFactory sonProxyFactory = new SonProxyFactory(zhang);

        // 调用工厂类对象的 getInstance 方法动态获取目标类的子类对象
        zhang = (Teacher) sonProxyFactory.getInstance();

        System.out.println(zhang);
        //Teacher$$EnhancerByCGLIB$$be941ecd :::: net.sf.cglib.proxy.MethodProxy@5a2e4553
        //toString ::: 方法被调用前的预处理代码
        //toString ::: 方法被调用后的预处理代码
        //com.zhiyou100.test.test04.proxy.Teacher@28c97a5

    }
}

/**
 * 1 、创建子类工厂类，实现接口 MethodInterceptor
 */
class SonProxyFactory implements MethodInterceptor {
    /**
     * 2、定义成员变量，记录目的对象
     */
    public Object target;

    /**
     * 通过构造方法关联目标对象
     *
     * @param target
     */
    public SonProxyFactory(Object target) {
        this.target = target;
    }

    /**
     * 3、目标对象的方法被调用时， intercept 方法就会执行
     *
     * @param o
     * @param method
     * @param objects
     * @param methodProxy
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println(o.getClass().getSimpleName() + " :::: " + methodProxy);
        System.out.println(method.getName() + " ::: " + "方法被调用前的预处理代码");

        Object invoke = method.invoke(target, objects);

        System.out.println(method.getName() + " ::: " + "方法被调用后的预处理代码");
        return invoke;
    }

    /**
     * 4 定义一个动态生成 目标类的子类对象
     *
     * @return
     */
    public Object getInstance() {
        // 4.1 创建加强工具类
        Enhancer er = new Enhancer();
        // 4.2 指定要加强的父类（目标类）
        er.setSuperclass(target.getClass());
        // 4.3 设置回掉函数
        er.setCallback(this);
        // 4.4 返回一个子类对象
        return er.create();

    }
}

/**
 * 5、定义目标类
 */
class Teacher {
    int age;
    String name;

    public Teacher(int age, String name) {
        this.age = age;
        this.name = name;
    }

    /**
     * 目标类必须定义无参数的构造方法
     */
    public Teacher() {
    }

    void hehe() {
        System.out.println("老师 " + age + "   " + name);
    }

    void teach() {
        System.out.println("老师 " + name + " 在教书  ");

    }
}
